use std::slice;

use crate::{application::Application, service::service::Service};

use common::{
    base::status::Status,
    protocol::{protocol_v1::ProtocolV1Writer, MsgType},
    serial::request_message::RequestMessage,
    service::{
        sys_service_api::xport_service::{
            ChannelId, ConnIds, LoadServiceRequest, ServiceInfo, ServiceInfos, UnloadServiceRequest,
        },
        ServiceKey,
    },
};

use semver::Version;
use tracing::{debug, error, info};

use super::{
    get_local_service, pack_and_return_error, pack_and_return_message, pack_and_return_status,
    pack_and_return_success,
};
/**
 * 加载服务
 */
pub extern "C" fn load_service(service_id: i64, request_id: i64, param: *const u8, len: u32) {
    let slice = unsafe { std::slice::from_raw_parts(param, len as usize) };

    let mut load_service_request = LoadServiceRequest::default();

    load_service_request.parse_from_bytes(slice).unwrap();

    tokio::spawn(async move {
        //
        let local_service = get_local_service(service_id, request_id, true).await;

        if local_service.is_none() {
            return;
        }
        let local_service = local_service.unwrap();

        let dxc_version = Version::parse(&load_service_request.dxc_version);
        if dxc_version.is_err() {
            pack_and_return_error(
                request_id,
                local_service.get_service_key(),
                Status::error("版本号错误".into()),
            );
            return;
        }
        let dxc_manager = local_service.airport.get_dxc_manager();
        let dxc_version = dxc_version.unwrap();
        let ret = dxc_manager
            .load_local_dxc(
                &load_service_request.dxc_name,
                &dxc_version,
                &load_service_request.service_name,
                &load_service_request.config,
            )
            .await;

        let status = if ret.is_err() {
            ret.err().unwrap()
        } else {
            Status::new(0, String::default())
        };
        pack_and_return_status(request_id, local_service.get_service_key(), status);
    });
}
/**
 * 卸载服务
 */
pub extern "C" fn unload_service(service_id: i64, request_id: i64, param: *const u8, len: u32) {
    let slice = unsafe { std::slice::from_raw_parts(param, len as usize) };

    let mut unload_service_request = UnloadServiceRequest::default();

    unload_service_request.parse_from_bytes(slice).unwrap();

    tokio::spawn(async move {
        let local_service = get_local_service(service_id, request_id, true).await;

        if local_service.is_none() {
            return;
        }
        let local_service = local_service.unwrap();
        let dxc_manager = local_service.airport.get_dxc_manager();

        let dxc_version = Version::parse(&unload_service_request.dxc_version);

        if dxc_version.is_err() {
            pack_and_return_error(
                request_id,
                local_service.get_service_key(),
                Status::error("版本解析出错!".into()),
            );
            return;
        }
        let dxc_version = dxc_version.unwrap();

        let local_dxc = dxc_manager
            .get_dxc_by_name_and_version_without_build(
                &unload_service_request.dxc_name,
                &dxc_version,
            )
            .await;

        if local_dxc.is_none() {
            pack_and_return_error(
                request_id,
                local_service.get_service_key(),
                Status::error("服务不存在！".into()),
            );
            return;
        }

        local_dxc
            .unwrap()
            .remove_local_service_by_name(&unload_service_request.service_name)
            .await;
        pack_and_return_success(request_id, local_service.get_service_key());
    });
}

// service 发送消息
pub extern "C" fn send_message(
    service_id: i64,
    request_id: i64,
    receiver_service_key_ptr: *const u8,
    receiver_service_key_len: u32,
    channel_id: i64,
    buffer: *const u8,
    buffer_size: u32,
) {
    let receiver_service_slice = unsafe {
        slice::from_raw_parts(receiver_service_key_ptr, receiver_service_key_len as usize)
    };

    let message = unsafe {
        let slice = std::slice::from_raw_parts(buffer, buffer_size as usize);
        slice.to_owned()
    };

    let mut receiver_service_key = ServiceKey::default();

    receiver_service_key
        .parse_from_bytes(receiver_service_slice)
        .unwrap();

    tokio::spawn(async move {
        let airport = Application::get_airport();
        let dxc_manager = airport.get_dxc_manager();
        let local_service = dxc_manager.get_local_service_by_id(service_id).await;
        if local_service.is_none() {
            error!("调用的服务已经下线!");
            return;
        }
        let local_service = local_service.unwrap();
        let sender_service_key = local_service.get_service_key();
        let mut v1_writer = ProtocolV1Writer::new(
            message.len() as u32,
            request_id,
            &sender_service_key,
            &receiver_service_key,
        );
        //
        v1_writer.write_conn_id(0);
        v1_writer.write_msg_type(MsgType::NormalMsg);
        v1_writer.write_msg_body(&message);
        //
        // local_service.add_waitting_request_id(request_id);
        debug!(
            "发送消息给:{:?}, 消息长度：{}  channel_id = {}",
            &receiver_service_key,
            v1_writer.msg_buffer.len(),
            channel_id
        );
        if channel_id == 0 {
            airport.message_in(0, v1_writer.msg_buffer).await;
        } else {
            airport
                .send_message_to_channel(channel_id, &v1_writer.msg_buffer)
                .await;
        }
    });
}

/**
 * 创建链接
 */
pub extern "C" fn build_channel(service_id: i64, request_id: i64, node_id: i64) {
    tokio::spawn(async move {
        let local_service = get_local_service(service_id, request_id, true).await;
        if local_service.is_none() {
            return;
        }
        let local_service = local_service.unwrap();
        //  执行任务
        let channel_message = local_service.airport.get_channel_manager();
        let session_id = channel_message.build_xprc_channel(node_id).await;
        if session_id.is_none() {
            pack_and_return_error(
                request_id,
                local_service.get_service_key(),
                Status::error("连接失败!".into()),
            );
        } else {
            pack_and_return_success(request_id, local_service.get_service_key());
        }
    });
}

/**
 *
 */
pub extern "C" fn get_all_local_service(service_id: i64, request_id: i64, filter_system: bool) {
    tokio::spawn(async move {
        let local_service = get_local_service(service_id, request_id, false).await;
        if local_service.is_none() {
            return;
        }
        let local_service = local_service.unwrap();

        let dxc_manager = local_service.airport.get_dxc_manager();

        let service_infos = dxc_manager.get_all_local_service_info(filter_system).await;

        pack_and_return_message(request_id, local_service.get_service_key(), service_infos);
    });
}

pub extern "C" fn add_channel_id_to_remote_services(
    service_id: i64,
    request_id: i64,
    channel_id: i64,
    buffer: *const u8,
    buffer_len: u32,
) {
    let slice = unsafe { std::slice::from_raw_parts(buffer, buffer_len as usize) };
    let mut service_infos = ServiceInfos::default();
    service_infos.parse_from_bytes(slice).unwrap();

    tokio::spawn(async move {
        let local_service = get_local_service(service_id, request_id, true).await;
        if local_service.is_none() {
            return;
        }
        //
        let local_service = local_service.unwrap();

        let dxc_manager = local_service.airport.get_dxc_manager();

        for service_info in service_infos.services {
            let version = Version::parse(&service_info.dxc_version);

            if version.is_err() {
                pack_and_return_error(
                    request_id,
                    local_service.get_service_key(),
                    Status::error("版本号格式错误！".into()),
                );
                return;
            }
            let version = version.unwrap();
            let dxc = dxc_manager
                .get_dxc_by_name_and_version(&service_info.dxc_name, &version)
                .await;

            dxc.add_channel_to_remote_service(&service_info.service_name, channel_id)
                .await;
        }
        pack_and_return_success(request_id, local_service.get_service_key());
    });
    //
}

pub extern "C" fn set_channel_xrpc_port(
    service_id: i64,
    request_id: i64,
    channel_id: i64,
    port: i32,
) {
    tokio::spawn(async move {
        let local_service = get_local_service(service_id, request_id, true).await;
        if local_service.is_none() {
            return;
        }
        let local_service = local_service.unwrap();
        let channel_manager = local_service.airport.get_channel_manager();
        let channel = channel_manager.get_channel(channel_id).await;
        if channel.is_none() {
            pack_and_return_error(
                request_id,
                local_service.get_service_key(),
                Status::error("channel 不存在".into()),
            );
            return;
        }
        let channel = channel.unwrap();
        channel.set_channel_port(port as u16).await;
        pack_and_return_success(request_id, local_service.get_service_key());
    });
}

pub extern "C" fn get_xrpc_port(_service_id: i64, _request_id: i64) -> i32 {
    let airport = Application::get_airport();

    airport.xprc_net.listen_port as i32
}

pub extern "C" fn get_all_conn_id(service_id: i64, request_id: i64) {
    tokio::spawn(async move {
        let local_service = get_local_service(service_id, request_id, false).await;

        if local_service.is_none() {
            return;
        }

        let local_service = local_service.unwrap();

        let channel_manager = local_service.airport.get_channel_manager();

        let conn_id_vec = channel_manager.get_all_conn_id().await;

        let mut conn_ids = ConnIds::default();

        conn_ids.conn_id = conn_id_vec;

        pack_and_return_message(request_id, local_service.get_service_key(), conn_ids);
    });
}

pub extern "C" fn get_channel_id_by_conn_id(service_id: i64, request_id: i64, conn_id: i64) {
    tokio::spawn(async move {
        let local_service = get_local_service(service_id, request_id, false).await;

        if local_service.is_none() {
            return;
        }

        let local_service = local_service.unwrap();

        let channel_manager = local_service.airport.get_channel_manager();

        let channel_id = channel_manager.get_channel_by_conn_id(conn_id).await;

        let mut channel_id_info = ChannelId::default();

        channel_id_info.channel_id = channel_id;

        pack_and_return_message(request_id, local_service.get_service_key(), channel_id_info);
    });
}

pub extern "C" fn remove_remote_services_all_channel_id(
    service_id: i64,
    request_id: i64,
    channel_id: i64,
    buffer: *const u8,
    buffer_len: u32,
) {
    let slice = unsafe { std::slice::from_raw_parts(buffer, buffer_len as usize) };
    let mut service_info = ServiceInfo::default();
    service_info.parse_from_bytes(slice).unwrap();

    tokio::spawn(async move {
        let local_service = get_local_service(service_id, request_id, true).await;

        if local_service.is_none() {
            return;
        }

        let local_service = local_service.unwrap();

        let version = Version::parse(&service_info.dxc_version);

        if version.is_err() {
            pack_and_return_error(
                request_id,
                local_service.get_service_key(),
                Status::error("版本号格式错误！".into()),
            );
            return;
        }
        let channel_manager = local_service.airport.get_channel_manager();

        let conn_id = channel_manager.get_conn_id_by_channel_id(channel_id).await;

        if conn_id.is_none() {
            pack_and_return_success(request_id, local_service.get_service_key());
            return;
        }

        let version = version.unwrap();
        //
        let dxc_manager = local_service.airport.get_dxc_manager();

        let dxc = dxc_manager
            .get_dxc_by_name_and_version_without_build(&service_info.dxc_name, &version)
            .await;

        if dxc.is_none() {
            pack_and_return_success(request_id, local_service.get_service_key());
            return;
        }

        let remove_service = dxc
            .unwrap()
            .get_remote_service_by_name(&service_info.service_name)
            .await;

        if remove_service.is_some() {
            remove_service.unwrap().clear_channel();
        }
        pack_and_return_success(request_id, local_service.get_service_key());
    });
}
